﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using pdfebookcutter.Properties;
using iTextSharp.text.exceptions;
using Microsoft.VisualBasic;

namespace pdfebookcutter
{
    public partial class PdfShowPage : UserControl
    {
        public PdfShowPage()
        {
            InitializeComponent();
            CropAreas = new List<CropArea>();


            Width = (int)AnyBox.Width;
            Height = (int)AnyBox.Height;
        }

        public EditionOptions EditOptions { get; set; }
        public List<CropArea> CropAreas = new List<CropArea>();

        public HashSet<int> PageNums { get; set; }
        public PdfReaderContentParser Parser { get; set; }
        public PdfReader Reader { get; set; }

       public RectangleF AnyBox;
      
        WeakReference PdfImage = new WeakReference(null, false);

        RenderInformation RenderData
        {
            get;
            set;
        }


        private void PdfShowPage_Load(object sender, EventArgs e)
        {
            //ExpandableObjectConverter(Source, treeView1.Nodes);

  
         

         //   toolStripStatusLabel1.Text = BuildPageText();
        }

        public static RectangleF ToRectangle(iTextSharp.text.Rectangle r)
        {
            return RectangleF.FromLTRB(r.Left, r.Top, r.Right, r.Bottom);
        }

        private string BuildPageText()
        {
            return string.Join(",", ToSequences(PageNums));
        }

        private IEnumerable<string> ToSequences(IEnumerable<int> PageNums)
        {
            var iLast = -2;

            int iStart = -2;

            foreach (var i in PageNums)
            {
                if (iStart == -2)
                {
                    iStart = i;
                    iLast = i;
                }
                else if (iLast + 1 != i)
                {
                    if (iStart == iLast)
                        yield return iLast.ToString();
                    else
                        yield return iStart + ":" + iLast;

                    iStart = i;
                    iLast = i;
                }
                else
                {
                    iLast = i;
                }



            }

            if (iStart == iLast)
                yield return iLast.ToString();
            else
                yield return iStart + ":" + iLast;

        }



        //private void ExpandableObjectConverter(PdfDictionary Source, TreeNodeCollection treeNodeCollection)
        //{
        //    foreach (var p in Source)
        //    {
        //        var newnode = treeNodeCollection.Add(p.Key.ToString());
        //        if (p.Key.CompareTo(PdfName.PARENT) == 0)
        //            continue;
        //        ExpandNode(p.Value, newnode);


        //    }
        //}

        //HashSet<PdfObject> expanded = new HashSet<PdfObject>();

        //private void ExpandNode(PdfObject Value, TreeNode newnode)
        //{


        //    if (Value == null)
        //        return;

        //    if (!expanded.Add(Value))
        //        return;


        //    if (Value is PdfDictionary)
        //    {
        //        ExpandableObjectConverter(Value as PdfDictionary, newnode.Nodes);
        //        return;
        //    }

        //    if (Value is PdfArray)
        //    {
        //        ExpandableArrayConverter(Value as PdfArray, newnode.Nodes);
        //        return;
        //    }

        //    if (Value is PdfNumber)
        //    {
        //        AddNumber(Value as PdfNumber, newnode.Nodes);
        //        return;
        //    }

        //    if (Value is PRIndirectReference)
        //    {
        //        var r = Value as PRIndirectReference;
        //        ExpandReference(r, newnode.Nodes);


        //        return;
        //    }

        //    if (Value is PdfName)
        //    {
        //        newnode.Nodes.Add(Value.ToString());
        //        return;
        //    }


        //    System.Diagnostics.Trace.WriteLine("unknown type:" + Value.GetType().Name);
        //}

        //private void ExpandReference(PRIndirectReference r, TreeNodeCollection treeNodeCollection)
        //{

        //    var dst = r.Reader.GetPdfObject(r.Number);

        //    var refnode = treeNodeCollection.Add("ref" + r.Number);

        //    ExpandNode(dst, refnode);
        //}

        //private void AddNumber(PdfNumber pdfNumber, TreeNodeCollection treeNodeCollection)
        //{
        //    treeNodeCollection.Add(pdfNumber.ToString());
        //    //throw new NotImplementedException();
        //}

        //private void ExpandableArrayConverter(PdfArray pdfArray, TreeNodeCollection treeNodeCollection)
        //{
        //    int idx = 0;
        //    foreach (var p in pdfArray.ArrayList)
        //    {
        //        var newnode = treeNodeCollection.Add("[" + (idx++) + "]");

        //        ExpandNode(p, newnode);


        //    }
        //}


        //private void PdfShowPage_Paint(object sender, PaintEventArgs e)
        //{

        //    //var Mediabox = MakeRectangle(Source.Get(PdfName.MEDIABOX) as PdfArray);
        //    //var Cropbox = MakeRectangle(Source.Get(PdfName.CROPBOX) as PdfArray);
        //    //var Bleedbox = MakeRectangle(Source.Get(PdfName.BLEEDBOX) as PdfArray);
        //    //var Trimbox = MakeRectangle(Source.Get(PdfName.TRIMBOX) as PdfArray);
        //    //var Artbox = MakeRectangle(Source.Get(PdfName.ARTBOX) as PdfArray);

        //    //var Content = Source.Get(PdfName.CONTENTS) as PdfArray;
        //    //var Resources = Source.Get(PdfName.RESOURCES);
        //    //var Parent = Source.Get(PdfName.PARENT);
        //    //var Type = Source.Get(PdfName.TYPE);

        //    //if (Content != null)
        //    //{



        //    //    foreach (var reference in Content.ArrayList.OfType<PdfIndirectReference>())
        //    //    {
        //    //        var r = reference as PRIndirectReference;
        //    //        var dst = r.Reader.GetPdfObject(reference.Number) as PdfDictionary;

        //    //        var l = dst.Get(PdfName.FILTER);
        //    //    }
        //    //}

        //    //if(Cropbox.HasValue)
        //    //    e.Graphics.DrawRectangle(Pens.Black, Rectangle.Round(Cropbox.Value));
        //}

        private RectangleF? MakeRectangle(PdfArray pdfArray)
        {
            if (pdfArray == null)
                return null;



            var Values = pdfArray.ArrayList.OfType<PdfNumber>().ToArray();

            if (Values.Length != 4)
                return null;

            return RectangleF.FromLTRB(Values[0].FloatValue, Values[1].FloatValue, Values[2].FloatValue, Values[3].FloatValue);


        }


        public class RenderInformation : IRenderListener
        {
            public List<ImageRenderInfo> Images { get; protected set; }
            public List<TextRenderInfo> Texts { get; protected set; }

            public RectangleF[] imageRects { get; protected set; }
            public RectangleF[] alltextrects { get; protected set; }

            public IEnumerable<RectangleF> AllRects { get { return imageRects.Concat(alltextrects); } }

            public bool Valid { get; protected set; }

            public RenderInformation()
            {
                Images = new List<ImageRenderInfo>();
                Texts = new List<TextRenderInfo>();

                imageRects = new RectangleF[] { };
                alltextrects = new RectangleF[] { };

                Valid = false;
            }

            public RenderInformation(PdfReaderContentParser Parser, IEnumerable<int> PageNums)
                : this()
            {
                foreach (var PageNum in PageNums)
                    Parser.ProcessContent(PageNum, this);

                imageRects = Images.Select(t => RetrieveImageRect(t)).Select(r => Normalize(r)).ToArray();
                alltextrects = Texts.Select(t => RetrieveRect(t)).Select(r => Normalize(r)).ToArray();

                Valid = true;
            }

            public RenderInformation(MDIParent Parent, PdfReaderContentParser Parser, IEnumerable<int> PageNums)
                : this()
            {
                foreach (var PageNum in PageNums)
                {
                    var num = PageNum;

                    Parent.ScheduleAction(() => Parser.ProcessContent(num, this), () => { });
                }

                Parent.ScheduleAction(() =>
                {

                    imageRects = Images.Select(t => RetrieveImageRect(t)).Select(r => Normalize(r)).Where(f => f.Width > 2 && f.Height > 2).ToArray();
                    alltextrects = Texts.Select(t => RetrieveRect(t)).Select(r => Normalize(r)).Where(f => f.Width > 2 && f.Height > 2).ToArray();
                }, () => { Valid = true; });

            }


            public void BeginTextBlock()
            {

            }

            public void EndTextBlock()
            {

            }

            public void RenderImage(ImageRenderInfo renderInfo)
            {
                Images.Add(renderInfo);
            }

            public void RenderText(TextRenderInfo renderInfo)
            {
                Texts.Add(renderInfo);
                //var text = renderInfo.GetText();

            }
        }


         



        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            var g = e.Graphics;

            try
            {
               


                var CachedBitmap = PdfImage.Target as Bitmap;

                if (RenderData == null)
                {
                    CachedBitmap = Resources.history;
                }
                else
                {
                    if (CachedBitmap == null)
                    {
                        CachedBitmap = new Bitmap(Width, Height, g);

                        using (var gCache = Graphics.FromImage(CachedBitmap))
                        {
                            MoveOrigin(gCache);
                            foreach (var i in RenderData.Images)
                            {

                                var dstRect = RetrieveImageRect(i);
                                Image img;
                                try
                                {
                                    img = i.GetImage().GetDrawingImage();

                                }
                                catch (UnsupportedPdfException)
                                {
                                    img = null;
                                }
                                catch (ArgumentException)
                                {
                                    img = null;
                                }


                                if (img != null)
                                    gCache.DrawImage(img, dstRect);
                            }

                            if (RenderData.imageRects.Any())
                                gCache.FillRectangles(new SolidBrush(Color.FromArgb(64, Color.Yellow)), RenderData.imageRects);

                            if (RenderData.alltextrects.Any())
                                gCache.FillRectangles(new SolidBrush(Color.FromArgb(64, Color.Red)), RenderData.alltextrects);



                        }
                        PdfImage.Target = CachedBitmap;
                    }
                }

                if (CachedBitmap != null)
                {
                    g.DrawImageUnscaled(CachedBitmap, 0, 0);
                }
              



                MoveOrigin(g);
                if (CropAreas.Any())
                {
                    var GripperBrush = new SolidBrush(Color.FromArgb(64, Color.Blue));

                    g.FillRectangles(GripperBrush, CropPaintAreas.ToArray());


                    //var PenBrush = new HatchBrush(HatchStyle.Cross, Color.FromArgb(64, Color.Blue));
                    var pathpen = new Pen(GripperBrush, GripperSize);
                    pathpen.StartCap = LineCap.RoundAnchor;
                    pathpen.EndCap = LineCap.ArrowAnchor;

                    g.DrawPath(pathpen, new GraphicsPath(CropAreas.Select(a => a.MiddlePoint).ToArray(),
                        Enumerable.Repeat((byte)(PathPointType.Line | PathPointType.DashMode), CropAreas.Count).ToArray(), FillMode.Alternate));
                }

              
                //           foreach (var t in Texts)
                //           {
                //               var dstRect = RetrieveRect(t);

                ////               var s= new StringFormat(); s.

                //        //       g.DrawString(t.GetText(), DefaultFont, Brushes.Black, dstRect);
                //               var yourtext = t.GetText();

                //               SizeF string_size;
                //               var LabelFont = DefaultFont;
                //               do
                //               {
                //                   LabelFont = new Font(LabelFont.Name, LabelFont.Size - 1, FontStyle.Bold, GraphicsUnit.Pixel);
                //                   string_size = e.Graphics.MeasureString(yourtext, DefaultFont);
                //               }
                //               while ((string_size.Width > dstRect.Width || string_size.Height > dstRect.Height) && LabelFont.Size > 2);
                //               g.DrawString(t.GetText(), LabelFont, Brushes.Black, dstRect);

                //           }
                
            }
            catch (Exception exception)
            {
                g.ResetTransform();
                g.DrawString("Error: " + exception.Message, DefaultFont, Brushes.Black, 0, 0);
                //throw;
            }
        }


        private void PdfShowPage_Resize(object sender, EventArgs e)
        {
            if (PdfImage.Target != null)
            {
                (PdfImage.Target as IDisposable).Dispose();
                PdfImage.Target = null;
            }
            Invalidate();

        }


        public class CropArea : ICloneable
        {
            [Flags]
            public enum HitTestFlag
            {
                Zero = 0,
                Top = 1,
                Bottom = 2,
                Right = 4,
                Left = 8,
                All = 15
            }

            RectangleF c;


            public CropArea(RectangleF croppingrect)
            {
                c = croppingrect;
            }



            public RectangleF Area { get { return c; } set { c = value; } }

            public PdfArray PdfValueArray
            {
                get
                {
                    PdfArray rectArray = new PdfArray();
                    
                    rectArray.Add(new PdfNumber(c.Left));
                    rectArray.Add(new PdfNumber(c.Bottom));
                    rectArray.Add(new PdfNumber(c.Right));
                    rectArray.Add(new PdfNumber(c.Top));
                    return rectArray;
                }
            }


            public RectangleF NormalizedRect
            {
                get
                {
                    RectangleF r = c;
                    
                    if(r.Width < 0)
                    { r.X += r.Width; r.Width = -r.Width; }

                    if (r.Height< 0)
                    { r.Y += r.Height; r.Height = -r.Height; }
                    
                    return r;
                }
            }


            public RectangleF r
            {
                get
                {
                    RectangleF r = NormalizedRect;
                    var cWidth = r.Width;
                    r.Width = Math.Min(r.Width / 2 - 1, GripperSize);
                    r.X += cWidth - r.Width; 
                    return r;
                }
            }
            public RectangleF t
            {
                get
                {
                    RectangleF t = NormalizedRect;
                    t.Height = Math.Min(t.Height / 2 - 1, GripperSize);
                    return t;
                }
            }
            public RectangleF b
            {
                get
                {
                    RectangleF b = NormalizedRect;
                    var cHeight = b.Height;
                    b.Height = Math.Min(b.Height / 2 - 1, GripperSize);
                    b.Y += cHeight - b.Height;
                    return b;
                }
            }
            public RectangleF l
            {
                get
                {
                    RectangleF l = NormalizedRect;
                    l.Width = Math.Min(l.Width / 2 - 1, GripperSize);

                    return l;
                }
            }

            public IEnumerable<RectangleF> AllRects
            {

                get
                {
                    yield return NormalizedRect;
                    yield return r;
                    yield return t;
                    yield return b;
                    yield return l;
                }
            }

            public HitTestFlag HitTest(PointF p)
            {
                HitTestFlag returnValue = HitTestFlag.Zero;

                if (r.Contains(p))
                    returnValue |= HitTestFlag.Right;

                if (l.Contains(p))
                    returnValue |= HitTestFlag.Left;

                if (t.Contains(p))
                    returnValue |= HitTestFlag.Top;

                if (b.Contains(p))
                    returnValue |= HitTestFlag.Bottom;

                if (c.Contains(p) && returnValue == HitTestFlag.Zero)
                    returnValue = HitTestFlag.All;

                return returnValue;
            }


            public void Drag(SizeF Difference, HitTestFlag hitTestFlag)
            {
                if (hitTestFlag.HasFlag(HitTestFlag.Right))
                    c.Width += Difference.Width;

                if (hitTestFlag.HasFlag(HitTestFlag.Bottom))
                    c.Height+= Difference.Height;

                if (hitTestFlag.HasFlag(HitTestFlag.Left))
                { c.X += Difference.Width; c.Width -= Difference.Width; }

                if (hitTestFlag.HasFlag(HitTestFlag.Top))
                { c.Y += Difference.Height; c.Height -= Difference.Height; }

            }

            public bool IsEmpty
            {
                get
                {
                    return Width < 1 || Height < 1;
                }
            }

            public float Width { get { return c.Width; } set { c.Width = value;  } }
            public float Height { get { return c.Height; } set { c.Height = value; } }
            public float X { get { return c.X; } set { c.X = value; } }
            public float Y { get { return c.Y; } set { c.Y = value; } }

            public PointF MiddlePoint
            {
                get { return new PointF(X + Width / 2.0f, Y + Height / 2.0f); }

            }

            internal void DoNormalizeRect()
            {
                c = NormalizedRect;
            }

            public float Top { get { return c.Y; } set { c.Y = value; } }
            public float Bottom { get { return c.Y + c.Height; } set { c.Height = value - c.Y; } }

            public float Left { get { return c.X; } set { c.X = value; } }
            public float Right { get { return c.X + c.Width; } set { c.Width = value - c.X; } }

            public object Clone()
            {
                return this.MemberwiseClone();
            }

            public void KeepRatio(float Ratio, HitTestFlag hitTestFlag)
            {
                if (hitTestFlag.HasFlag(HitTestFlag.Left) || hitTestFlag.HasFlag(HitTestFlag.Right))
                {
                    Height = Width * Ratio;
                }
                if (hitTestFlag.HasFlag(HitTestFlag.Top) || hitTestFlag.HasFlag(HitTestFlag.Bottom))
                {
                    Width = Height / Ratio;
                }
            }
        }

        public const float GripperSize = 10;
        private IEnumerable<RectangleF> CropPaintAreas
        {
            get 
            {
                return CropAreas.SelectMany(c => c.AllRects);
            }
        }

        public static RectangleF Normalize(RectangleF r)
        {
            return RectangleF.FromLTRB(
                Math.Min(r.Left, r.Right),
                Math.Min(r.Top, r.Bottom),
                Math.Max(r.Left, r.Right),
                Math.Max(r.Top, r.Bottom));
        }


        protected static RectangleF RetrieveRect(TextRenderInfo t)
        {
            return RectangleF.Union(
                            ToRectangle(t.GetBaseline().GetBoundingRectange()),
                            RectangleF.Union(
                            ToRectangle(t.GetAscentLine().GetBoundingRectange()),
                            ToRectangle(t.GetDescentLine().GetBoundingRectange())));
        }


        protected static RectangleF RetrieveImageRect(ImageRenderInfo i)
        {

            var pdfMatrix = i.GetImageCTM();


            var tl = ToPoint(new Vector(0, 0, 1).Cross(pdfMatrix));
            var br = ToPoint(new Vector(1, 1, 1).Cross(pdfMatrix));

            var dstRect = RectangleF.FromLTRB(tl.X, br.Y, br.X, tl.Y);
            return dstRect;
        }

        private System.Drawing.Drawing2D.Matrix ToGDIMatrix(iTextSharp.text.pdf.parser.Matrix pdfMatrix)
        {
            return new System.Drawing.Drawing2D.Matrix(
            pdfMatrix[iTextSharp.text.pdf.parser.Matrix.I11],
            pdfMatrix[iTextSharp.text.pdf.parser.Matrix.I12],
            pdfMatrix[iTextSharp.text.pdf.parser.Matrix.I21],
            pdfMatrix[iTextSharp.text.pdf.parser.Matrix.I22],
            pdfMatrix[iTextSharp.text.pdf.parser.Matrix.I31],
            pdfMatrix[iTextSharp.text.pdf.parser.Matrix.I32]);

        }

        private void MoveOrigin(Graphics g)
        {

            g.TranslateTransform(0, Height); g.ScaleTransform(1, -1); // set origin to bottom left

        }


        public static RectangleF ToRectangle(System.util.RectangleJ rectangleJ)
        {
            return new RectangleF(rectangleJ.X, rectangleJ.Y, rectangleJ.Width, rectangleJ.Height);
        }


        public static iTextSharp.text.Rectangle ToPdfRectangle(RectangleF r)
        {
            return new iTextSharp.text.Rectangle(r.Left, r.Top, r.Right, r.Bottom);
        }


        protected static PointF ToPoint(Vector vector)
        {
            return new PointF(vector[Vector.I1], vector[Vector.I2]);
        }

        


        private void toolStripButtonDoKMeanGrouping_Click(object sender, EventArgs e)
        {
         //   int nGroups = int.Parse(toolStripTextBox1.Text);


        }
        
    

        PointF? DraggingStartPoint;
        CropArea SelectedArea;
        CropArea.HitTestFlag? HitTestInfo;

        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            DraggingStartPoint = ToAbsLocation(e.Location);

            SelectedArea = CropAreas.Where(a => a.HitTest(DraggingStartPoint.Value) != CropArea.HitTestFlag.Zero).FirstOrDefault();

            

            if (SelectedArea == null)
            {
                SelectedArea = new CropArea(new RectangleF(DraggingStartPoint.Value, new SizeF(0.5f,0.5f)));
                CropAreas.Add(SelectedArea);
                HitTestInfo = CropArea.HitTestFlag.Top | CropArea.HitTestFlag.Right;
            }
            else
            {
                HitTestInfo = SelectedArea.HitTest(DraggingStartPoint.Value);
            }

            if (HitTestInfo == CropArea.HitTestFlag.All)
            {
                if (ModifierKeys.HasFlag(Keys.Control))
                {
                    SelectedArea = SelectedArea.Clone() as CropArea;
                    
                    CropAreas.Add(SelectedArea);
                }

            }
        }

        private PointF ToAbsLocation(Point point)
        {
            return new PointF(point.X, Height -point.Y);
        }

        private void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            if (SelectedArea != null)
            { 
                SelectedArea.DoNormalizeRect();

                if (SelectedArea.IsEmpty)
                    CropAreas.Remove(SelectedArea);

                if ((ModifierKeys & Keys.Shift) == Keys.Shift || EditOptions.AutoSpring)
                {
                    ShrinkArea(SelectedArea);

                    if (EditOptions.KeepRatio.HasValue)
                        SelectedArea.KeepRatio(EditOptions.KeepRatio.Value, HitTestInfo.Value);


                }
            }

            SelectedArea = null;
            DraggingStartPoint = null;
            HitTestInfo = null;

            Invalidate();
        }

        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if(DraggingStartPoint == null || SelectedArea == null || HitTestInfo == null)
                return;

            var CurrentLocation = ToAbsLocation(e.Location);

            var Difference = SizeF.Subtract(new SizeF(CurrentLocation), new SizeF(DraggingStartPoint.Value));

            SelectedArea.Drag(Difference, HitTestInfo.Value);
          
            if (EditOptions.KeepRatio.HasValue)
                SelectedArea.KeepRatio(EditOptions.KeepRatio.Value, HitTestInfo.Value);

            Invalidate();

            DraggingStartPoint = CurrentLocation;
        }

        private void PdfShowPage_MouseClick(object sender, MouseEventArgs e)
        {
                var location = ToAbsLocation(e.Location);
            var AreaUnderCursor = CropAreas.Where(a => a.HitTest(location) != CropArea.HitTestFlag.Zero).FirstOrDefault();

            if ((ModifierKeys & Keys.Control) == Keys.Control)
            {
                contextMenuStrip1.Tag = AreaUnderCursor;
                moveLastToolStripMenuItem_Click(this, EventArgs.Empty);
            }

            if (e.Button == System.Windows.Forms.MouseButtons.Right && AreaUnderCursor != null)
            {
                contextMenuStrip1.Tag = AreaUnderCursor;
                contextMenuStrip1.Show(PointToScreen(e.Location));
            }
        }

        private void MenuAction(Action<CropArea> Action)
        {

            var Area = contextMenuStrip1.Tag as CropArea;
            if (Area == null)
                return;

            Action(Area);

            Invalidate();
        }

        private void moveFirstToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MenuAction(Area =>
            {   
                CropAreas.Remove(Area);
                CropAreas.Insert(0, Area);
            });
        }

        private void moveUpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MenuAction(Area =>
            {
                int iIndexBefore = CropAreas.IndexOf(Area);
                if (iIndexBefore <= 0)
                    return; 
                CropAreas.Remove(Area);
                CropAreas.Insert(iIndexBefore - 1, Area);
            }); 
           
        }

        private void moveDownToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MenuAction(Area =>
           {

               int iIndexBefore = CropAreas.IndexOf(Area);
               if (iIndexBefore >= CropAreas.Count - 1)
                   return;

               CropAreas.Remove(Area);
               CropAreas.Insert(iIndexBefore + 1, Area);

           });
        }

        private void moveLastToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MenuAction(Area =>
           {

               CropAreas.Remove(Area);
               CropAreas.Insert(CropAreas.Count, Area);
           });
        }

        private void removeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MenuAction(Area =>
          {
              CropAreas.Remove(Area);
          });
        }

        internal void RemoveAllAreas()
        {
            MenuAction(Area =>
          {
              CropAreas.Clear();
          });
        }

        private void springToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MenuAction(Area =>
          {
              ShrinkArea(Area);
          });
            
        }

        private void ShrinkArea(CropArea Area)
        {
            var Allrectangles = RenderData.AllRects;

            var AreaRect = Area.NormalizedRect;
            var MatchingRects = Allrectangles.Where(a => AreaRect.Contains(a) || a.IntersectsWith(AreaRect)).ToArray();

            var spanningArea = GetSpanningArea(MatchingRects);
            Area.Area = spanningArea;

            Area.DoNormalizeRect();
        }

        private static RectangleF GetSpanningArea(IEnumerable<RectangleF> MatchingRects)
        {
            var newL = MatchingRects.Min(r => r.Left);
            var newR = MatchingRects.Max(r => r.Right);
            var newT = MatchingRects.Min(r => r.Top);
            var newB = MatchingRects.Max(r => r.Bottom);

            var spanningArea = RectangleF.FromLTRB(newL, newT, newR, newB); ;
            return spanningArea;
        }

        private void removeAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CropAreas.Clear();
            Invalidate();
        }

        private void autoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CropAreas.Clear();

            // start kmeans

            var r = new Random();

            var Centers = Enumerable.Range(0, 3).Select(i => new PointF(AnyBox.Width * (float)r.NextDouble(), AnyBox.Height * (float)r.NextDouble())).ToArray();

            for (int i = 0; i < 4; i++)
            {
                var CoordAssignment = RenderData. alltextrects.GroupBy(rect => NearestCenter(rect, Centers));

                Centers = CoordAssignment.Select(group => MeanPoint(group.AsEnumerable())).ToArray();
            }
            var LastCoordAssignment = RenderData.alltextrects.GroupBy(rect => NearestCenter(rect, Centers));

            foreach (var group in LastCoordAssignment)
            {
                var spanningArea = GetSpanningArea(group);

                CropAreas.Add(new CropArea(spanningArea));

            }

            //// start from top to bottom, and count number of shapes in line
            ////
            //var AverageHeight = alltextrects.Average(r => r.Height);

            //var YCoords = alltextrects.SelectMany(r => new float[] { r.Top,- r.Bottom }).OrderBy(f => Math.Abs(f)).ToArray();


            //List<float> YEmptyCoords = new List<float>();

            //int nY = 0;
            //foreach (var yitem in YCoords)
            //{
            //    System.Diagnostics.Trace.WriteLine(Math.Abs(yitem) + "\t" + nY);
            //    if (yitem > 0)
            //    {
            //        if (nY == 0)
            //        {
            //            YEmptyCoords.Add(yitem);
            //        }
                        
            //        nY++;
            //    }
            //    else
            //    {
            //        nY--;

            //        if (nY == 0)
            //        {
            //            YEmptyCoords.Add(-yitem);
            //        }

            //    }
            //    System.Diagnostics.Trace.WriteLine(Math.Abs(yitem) + "\t" + nY);
            //}

            

        }

        private PointF MeanPoint(IEnumerable<RectangleF> iEnumerable)
        {
            return new PointF(iEnumerable.Average(r => r.X), iEnumerable.Average(r => r.Y));
        }

        private PointF NearestCenter(RectangleF r, PointF[] Centers)
        {
            return Centers
                .OrderByDescending(center =>
                    Math.Max(
                        Math.Max(
                            Math.Abs(r.Left - center.X), 
                            Math.Abs(r.Top - center.Y)),
                        Math.Max(
                            Math.Abs(r.Right - center.X), 
                            Math.Abs(r.Bottom- center.Y)
                            )
                            )
                            )
                    .First();
        }

        public void SchedulePageSizeActions(MDIParent Parent)
        {

            Parent.ScheduleAction(() =>
                GetPageSize(), () => { });
        }

        public void AdjustPageSize()
        {

           
                    Width = (int)AnyBox.Width;
                    Height = (int)AnyBox.Height;
                
        }


        public void ScheduleActions(MDIParent Parent)
        {

            var data = new RenderInformation(Parent, Parser, PageNums);
            var pThis = this;

            Parent.ScheduleAction(() => { }, () => { pThis.RenderData = data; pThis.Invalidate(); });
        }

        public void GetPageSize()
        {
            
            var AllRects = PageNums.Select(p => Reader.GetPageSize(p)).Select(r => ToRectangle(r));

            AnyBox = AllRects.Aggregate(
                RectangleF.Empty,
                (old, current) => old == RectangleF.Empty ? current : RectangleF.Union(old, current),
                r => Normalize(r));


       

        //    var p = PageNums.First();
            
        //    var Source = Reader.GetPageN(p);


        //    var Mediabox = MakeRectangle(Source.Get(PdfName.MEDIABOX) as PdfArray);
        //    var Cropbox = MakeRectangle(Source.Get(PdfName.CROPBOX) as PdfArray);
        //    var Bleedbox = MakeRectangle(Source.Get(PdfName.BLEEDBOX) as PdfArray);
        //    var Trimbox = MakeRectangle(Source.Get(PdfName.TRIMBOX) as PdfArray);
        //    var Artbox = MakeRectangle(Source.Get(PdfName.ARTBOX) as PdfArray);

        //    AnyBox = Mediabox
        //      ?? Cropbox
        //      ?? Bleedbox
        //      ?? Trimbox
        //      ?? Artbox
        //      ?? new RectangleF(0, 0, 400, 600);

         

        }

        private void presetsToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void addToPresetsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string name = Interaction.InputBox("Name of the new preset");

            if (string.IsNullOrWhiteSpace(name))
                return;
   
            if(Settings.Default.Presets == null)
                Settings.Default.Presets = new PresetList();


            Settings.Default.Presets.Add(new Preset() { Name = name, Rects = CropAreas.Select(c => c.NormalizedRect).ToArray() });

            Settings.Default.Save();
        }

        private void removeFromPresetsToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void addToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {

            PopulatePresets();
        }

        private void PopulatePresets()
        {
            if (Settings.Default.Presets == null)
                Settings.Default.Presets = new PresetList();

            removeFromPresetsToolStripMenuItem.DropDownItems.Clear();
            presetsToolStripMenuItem.DropDownItems.Clear();

            foreach (var p in Settings.Default.Presets)
            {
                var currentPreset = p;
                var newSelectItem = presetsToolStripMenuItem.DropDownItems.Add(p.Name);
                newSelectItem.Click += (eventa, obj) => { CropAreas.AddRange(currentPreset.Rects.Select(c => new CropArea(c))); Invalidate(); };

                var newRemoveItem = removeFromPresetsToolStripMenuItem.DropDownItems.Add(p.Name);
                newRemoveItem.Click += (eventa, obj) => { Settings.Default.Presets.Remove(p); Settings.Default.Save(); };


            }
        }


       
    }
}
